package com.fq.ability.shiro.jwt;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.fq.ability.redis.constant.RedisConstant;
import com.fq.api.api.ApiError;
import com.fq.api.api.ApiRest;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.http.HttpStatus;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author 超chao
 * @Description 鉴权登录拦截器
 * @Date 2024/10/12/周六 14:56
 * @Version 1.0
 */
@Log4j2
public class JwtFilter extends BasicHttpAuthenticationFilter {

    /**
     * 跨域请求
     */
    private static final String CROSS_OPTIONS = "OPTIONS";

    /**
     * 执行登录认证
     *
     * @param servletRequest
     * @param servletResponse
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //这几句代码是关键
        if (CROSS_OPTIONS.equals(request.getMethod())) {
            response.setStatus(HttpStatus.SC_NO_CONTENT);
            return true;
        }

        return this.executeLogin(servletRequest, servletResponse);
    }


    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String authorizationHeader = httpServletRequest.getHeader(RedisConstant.AUTHORIZATION);
        // 检查Authorization头是否存在并且格式正确
        if (StrUtil.isNotBlank(authorizationHeader) && authorizationHeader.startsWith(RedisConstant.BEARER)) {
            String token = authorizationHeader.substring(RedisConstant.BEARER_SPLIT); // 去掉 "Bearer " 前缀

            // 提交给realm进行登入，如果错误他会抛出异常并被捕获
            try {
                SecurityUtils.getSubject().login(new JwtToken(token));
                return true;
            } catch (Exception e) {
                request.setAttribute(getFailureKeyAttribute(), e);
                // 捕获异常并返回false即可，下一步给onAccessDenied去处理
                return false;
            }
        } else {
            // 如果Authorization头不存在或格式不正确，可以记录日志或直接返回false
            request.setAttribute(getFailureKeyAttribute(), new AuthenticationException(ApiError.ERROR_10020001.msg));
            return false;
        }
    }

    /**
     * 执行授权错误时的方法
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json");
        httpServletResponse.setStatus(HttpStatus.SC_OK);
        // 获取异常信息
        Exception e = (Exception) request.getAttribute(getFailureKeyAttribute());
        if (e == null) {
            e = new Exception("Unknown error");
        }
        ApiRest<Void> apiRest = createApiRest(e);
        httpServletResponse.getWriter().print(JSON.toJSONString(apiRest));
        return false;
    }

    protected String getFailureKeyAttribute() {
        return "shiroLoginFailure";
    }

    private ApiRest<Void> createApiRest(Exception e) {
        String message = e.getMessage();
        if (message == null) {
            message = "Unknown error";
        }

        if (ApiError.ERROR_10020001.msg.equals(message)) {
            return new ApiRest<Void>().setMsg(ApiError.ERROR_10020001.msg).setCode(ApiError.ERROR_10020001.getCode());
        } else if (ApiError.ERROR_10020024.msg.equals(message)) {
            return new ApiRest<Void>().setMsg(ApiError.ERROR_10020024.msg).setCode(ApiError.ERROR_10020024.getCode());
        } else {
            return new ApiRest<Void>().setMsg(message).setCode(1);
        }
    }


}